{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "63439ab2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'hellow'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import os\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "import torchvision\n",
    "from torch.utils.data import Dataset, DataLoader, ConcatDataset\n",
    "from torchvision import transforms\n",
    "import copy\n",
    "import tqdm\n",
    "from PIL import Image\n",
    "\n",
    "%matplotlib inline\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签\n",
    "plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号\n",
    "filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f204e2b6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'hellow'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 加载数据集\n",
    "train_dir = r\"..\\01_数据集\\01_train\"\n",
    "test_dir = r\"..\\01_数据集\\02_test\"\n",
    "\n",
    "train_files = os.listdir(train_dir)\n",
    "test_files = os.listdir(test_dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c91e139e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'hellow'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class CatDogDataset(Dataset):\n",
    "    def __init__(self, file_list, dir, mode='train', transform=None):\n",
    "        self.file_list = file_list\n",
    "        self.dir = dir\n",
    "        self.mode = mode\n",
    "        self.transform = transform\n",
    "        if self.mode == 'train':\n",
    "            if 'dog' in self.file_list[0]:\n",
    "                self.label = 1\n",
    "            else:\n",
    "                self.label = 0\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.file_list)\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        img = Image.open(os.path.join(self.dir, self.file_list[idx]))\n",
    "        if self.transform:\n",
    "            img = self.transform(img)\n",
    "        if self.mode == 'train':\n",
    "            img = img.numpy()\n",
    "            return img.astype('float32'), self.label\n",
    "        else:\n",
    "            img = img.numpy()\n",
    "            return img.astype('float32'), self.file_list[idx]\n",
    "\n",
    "data_transform = transforms.Compose([\n",
    "    transforms.Resize(256),\n",
    "    transforms.ColorJitter(),\n",
    "    transforms.RandomCrop(224),\n",
    "    transforms.RandomHorizontalFlip(),\n",
    "    transforms.Resize(128),\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "cat_files = [tf for tf in train_files if 'cat' in tf]\n",
    "dog_files = [tf for tf in train_files if 'dog' in tf]\n",
    "\n",
    "cats = CatDogDataset(cat_files, train_dir, transform=data_transform)\n",
    "dogs = CatDogDataset(dog_files, train_dir, transform=data_transform)\n",
    "\n",
    "catdogs = ConcatDataset([cats, dogs])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e39475aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "dataloader = DataLoader(catdogs, batch_size=16, shuffle=True, num_workers=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "72b9158f",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Downloading: \"https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth\" to C:\\Users\\mubai/.cache\\torch\\checkpoints\\alexnet-owt-4df8aa71.pth\n",
      "100%|████████████████████████████████████████████████████████████████| 244418560/244418560 [04:54<00:00, 829110.81it/s]\n"
     ]
    }
   ],
   "source": [
    "device = 'cuda'\n",
    "model = torchvision.models.alexnet(pretrained=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a4933e4c",
   "metadata": {},
   "outputs": [],
   "source": [
    "num_ftrs = model.classifier[6].in_features\n",
    "model.classifier[6] = nn.Linear(num_ftrs, 2)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a7aaf7da",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = model.to(device)\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.002, amsgrad=True)\n",
    "scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[500, 1000, 1500], gamma=0.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "97d7dbc1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Epoch 1/3] Iteration 70 -> Train Loss: 2.0586, Accuracy: 0.438\n",
      "[Epoch 2/3] Iteration 140 -> Train Loss: 0.6948, Accuracy: 0.625\n",
      "[Epoch 3/3] Iteration 210 -> Train Loss: 0.6948, Accuracy: 0.500\n"
     ]
    }
   ],
   "source": [
    "epochs = 3\n",
    "itr = 1\n",
    "p_itr = 70\n",
    "model.train()\n",
    "total_loss = 0\n",
    "loss_list = []\n",
    "acc_list = []\n",
    "for epoch in range(epochs):\n",
    "    for samples, labels in dataloader:\n",
    "        samples, labels = samples.to(device), labels.to(device)\n",
    "        optimizer.zero_grad()\n",
    "        output = model(samples)\n",
    "        loss = criterion(output, labels)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        total_loss += loss.item()\n",
    "        scheduler.step()\n",
    "\n",
    "        if itr % p_itr == 0:\n",
    "            pred = torch.argmax(output, dim=1)\n",
    "            correct = pred.eq(labels)\n",
    "            acc = torch.mean(correct.float())\n",
    "            print('[Epoch {}/{}] Iteration {} -> Train Loss: {:.4f}, Accuracy: {:.3f}'.format(epoch + 1, epochs, itr, total_loss / p_itr, acc))\n",
    "            loss_list.append(total_loss / p_itr)\n",
    "            acc_list.append(acc)\n",
    "            total_loss = 0\n",
    "\n",
    "        itr += 1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "b01110fc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(loss_list, label='loss')\n",
    "plt.plot(acc_list, label='accuracy')\n",
    "plt.legend()\n",
    "plt.title('training loss and accuracy')\n",
    "plt.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "8bfd0d68",
   "metadata": {},
   "outputs": [],
   "source": [
    "filename_pth = '03_alexnet_cat_or_dog_model.pth'\n",
    "torch.save(model.state_dict(), filename_pth)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17760fda",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "\n",
    "第一段代码使用的是DenseNet121模型，这是一个深度卷积神经网络模型，主要用于图像分类任务。在这段代码中，首先加载了预训练的DenseNet121模型，然后获取了模型分类器（classifier）的输入特征数量（in_features），接着将分类器替换为一个新的全连接层（nn.Linear），这个新的全连接层有两个输出节点，对应于两个类别。\n",
    "\n",
    "ok第二段代码使用的是AlexNet模型，这也是一个深度卷积神经网络模型，主要用于图像分类任务。在这段代码中，首先加载了预训练的AlexNet模型，然后获取了模型分类器（classifier）的第7个元素的输入特征数量（in_features），接着将分类器的第7个元素替换为一个新的全连接层（nn.Linear），这个新的全连接层有两个输出节点，对应于两个类别。\n",
    "\n",
    "总的来说，这两段代码的主要区别在于使用的模型和修改分类器的方式。DenseNet121和AlexNet都是深度卷积神经网络模型，但它们的结构有所不同，因此需要使用不同的方法来修改分类器。\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "评价模型的好坏通常需要根据具体的应用场景和评估指标来进行。以下是一些常用的评估指标：\n",
    "\n",
    "准确率（Accuracy）：模型正确分类的样本数量占总样本数量的比例。准确率越高，模型的性能越好。\n",
    "\n",
    "精确率（Precision）：模型预测为正例的样本中真正为正例的比例。精确率越高，模型在预测正例时的可靠性越高。\n",
    "\n",
    "召回率（Recall）：模型正确预测为正例的样本数量占实际正例样本数量的比例。召回率越高，模型能够找到更多的真正正例。\n",
    "\n",
    "F1值：综合考虑精确率和召回率的一个指标，计算公式为2 * (精确率 * 召回率) / (精确率 + 召回率)。F1值越高，模型的综合性能越好。\n",
    "\n",
    "此外，还可以使用交叉验证等方法来评估模型的稳定性和泛化能力。\n",
    "\n",
    "对于DenseNet121和AlexNet这两个模型，它们都是经典的深度卷积神经网络模型，在图像分类任务上表现良好。具体哪个模型更好取决于数据集的特点、任务的需求以及训练和调参的技巧等因素。一般来说，可以通过对比不同模型在相同数据集上的评估指标来选择更适合的模型。\n",
    "\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3db0319f",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0243afc1",
   "metadata": {},
   "outputs": [],
   "source": [
    "#本地运行模型\n",
    "import torch\n",
    "from torchvision import transforms\n",
    "from PIL import Image\n",
    "model_path_file = r\"03_alexnet_cat_or_dog_model.pth\"\n",
    "dog_files = r\"..\\01_数据集\\02_test\\1.jpg\"\n",
    "cat_files = r\"..\\01_数据集\\02_test\\5.jpg\"\n",
    "img_file = cat_files"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "829cef3c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载模型\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model = torchvision.models.densenet121(pretrained=False)\n",
    "\n",
    "num_ftrs = model.classifier.in_features\n",
    "model.classifier = nn.Sequential(nn.Linear(num_ftrs, 500), nn.Linear(500, 2))\n",
    "model.load_state_dict(torch.load(model_path_file)) \n",
    "model = model.to(device)\n",
    "model.eval()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b760971b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 图片预处理\n",
    "transform = transforms.Compose([transforms.Resize((128, 128)), transforms.ToTensor()]) \n",
    "\n",
    "image = Image.open(img_file) \n",
    "image = transform(image).unsqueeze(0).to(device)\n",
    "# 预测\n",
    "with torch.no_grad(): \n",
    "    output = model(image)\n",
    "    pred = torch.argmax(output, dim=1).item()\n",
    "\n",
    "# 判断结果\n",
    "if pred == 0:\n",
    "    print(\"该图片是猫\")\n",
    "else: \n",
    "    print(\"该图片是狗\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
